U N I T Y F O R G A M E S  
U N I T Y 2 0 2 0 LT S E D I T I O N | E - B O O K  
Optimize Your  
Mobile Game  
Performance  
Contents  
Introduction . . . . . . . . . . . . . . . . . . . . .  
Profiling . . . . . . . . . . . . . . . . . . . . . .  
Memory . . . . . . . . . . . . . . . . . . . . . .  
Adaptive Performance . . . . . . . . . . . . . . . .  
Programming and code architecture . . . . . . . . . . .  
Project configuration.  
3
4
10  
14  
16  
.22  
24  
29  
37  
41  
43  
45  
48  
50  
51  
Assets . . . . . . . . . . . . . . . . . . . . . .  
Graphics and GPU optimization . . . . . . . . . . . .  
User interface . . . . . . . . . . . . . . . . . . .  
Audio . . . . . . . . . . . . . . . . . . . . . . .  
Animation . . . . . . . . . . . . . . . . . . . . .  
Physics . . . . . . . . . . . . . . . . . . . . . .  
Workflow and collaboration . . . . . . . . . . . . . .  
Unity Integrated Success . . . . . . . . . . . . . . .  
Conclusion . . . . . . . . . . . . . . . . . . . . .  
Introduction  
Optimizing your iOS and Android applications is an essential  
process that underpins the entire development cycle Mobile  
hardware continues to evolve, and a mobile game’s optimization –  
along with its art, game design, audio, and monetization strategy  
plays a key role in shaping the player experience  
Both iOS and Android have active user bases in the billions  
If your mobile game is highly optimized, it has a better chance  
at passing certification from platformꢀspecific stores To maximize  
your opportunity for success at launch and beyond, your aim is  
always twofold: building the slickest, most immersive experience  
and making it performant on the widest range of handhelds  
This guide assembles knowledge and advice from Unity’s expert  
team of software engineers Unity’s Accelerate Solutions games  
team has partnered with developers across the industry to help  
launch the best games possible Follow the steps outlined here to  
get the best performance from your mobile game while reducing  
its power consumption  
Note that many of the optimizations discussed here may introduce  
additional complexity, which can mean extra maintenance and  
potential bugs Balance performance gains against the time and  
labor cost when implementing these best practices  
Happy optimizing from the Unity team!  
©
2021 Unity Technologies  
Use the Unity Profiler to test performance and resource allocation for your application  
The Unity Profiler can help you detect the causes of  
any lags or freezes during runtime or understand what’s  
happening at a specific frame (point in time) Enable the  
CPU and Memory tracks by default You can monitor  
additional Profiler Modules (such as Renderer, Audio,  
Physics, etc ) if you have specific needs for your game  
(e g , physicsꢀheavy or musicꢀbased gameplay)  
Build the application to your device by checking  
Development.Build and Autoconnect.Profiler,  
or connect manually to accelerate app startup time  
Choose the target to profile The Record button  
tracks several seconds of your application’s playback  
ꢁ300 frames by default) Go to Unity.>.Preferences.ꢀ..  
Analysis.>.Profiler.>.Frame.Count to increase this as  
far as 2000 if you need longer captures This means  
that the Unity Editor has to do more CPU work and  
takes up more memory, but it can be useful depending  
on your specific scenario  
©
2021 Unity Technologies  
Use the Timeline view to determine if you are CPUꢀbound or GPUꢀbound  
This is an instrumentationꢀbased profiler that profiles code timings explicitly wrapped  
API calls) Also, when you’re using the Deep Profiling setting, Unity can profile the  
beginning and end of every function call in your script code to tell you exactly which  
part of your application is causing a slowdown (but this comes with extra overhead)  
When profiling your game, we recommend that you cover both spikes and the cost of  
an average frame in your game Understanding and optimizing expensive operations  
that occur each frame can be more useful for applications running below the target  
framerate When looking for spikes, explore expensive operations first (e g , physics,  
AI, animation) and garbage collection  
Click in the window to analyze a specific frame Next, use either Timeline or the  
Hierarchy view:  
Hierarchy shows the hierarchy of ProfileMarkers, grouped together This allows  
you to sort the samples based on time cost in milliseconds (Time.ms and  
Self.ms) You can also count the number of Calls to a function and the  
managed heap memory (GC.Alloc) on this frame  
Timeline shows a visual breakdown of the specific frame’s timings This allows  
you to visualize how the activities relate to one another and across different  
threads Use this to determine if you are CPUꢀbound or GPUꢀbound  
©
2021 Unity Technologies  
The Hierarchy view allows you to sort ProfileMarkers by time cost  
Read a complete overview of the Unity Profiler here Those new to profiling can  
Before optimizing anything in your project, save the Profiler data file Implement  
your changes and compare the saved data before and after the modification  
Rely on this cycle to improve performance: profile, optimize, and compare  
Then, rinse and repeat  
Profile.early.and.often.  
The Unity Profiler provides performance information about your application,  
but it can’t help you if you don’t use it Profile your project early in development,  
not just when you are close to shipping Investigate glitches or spikes as soon  
as they appear As you develop a “performance signature” of your project,  
you’ll be able to spot new issues more easily  
Don’t.optimize.blindly.  
Don’t guess or make assumptions about what is slowing your game’s performance  
Use the Unity Profiler and platformꢀspecific tools to locate what, specifically, is  
causing the lag  
©
2021 Unity Technologies  
Also, not every optimization described here will apply to your application  
Something that works well in one project may not translate to yours  
Identify genuine bottlenecks and concentrate your efforts on those  
Profile.on.the.target.device.  
While profiling in the Editor can give you a very rough idea of the relative  
performance of different systems in your game, there’s no substitute for the  
real thing Profile a development build on target devices whenever possible  
Remember to profile and optimize for the lowestꢀspec device you plan to support  
The Unity Profiler alone cannot see into every part of the engine Fortunately, iOS  
and Android both include native tools to help you test performance:  
(
Use.the.Profile.Analyzer  
This tool lets you aggregate multiple frames of Profiler data, then locate frames  
of interest Want to see what happens to the Profiler after you make a change to  
your project? The Compare view allows you to load and diff two data sets, which  
is vital for testing changes and showing improvements The Profile Analyzer is  
available via Unity’s Package Manager  
©
2021 Unity Technologies  
Need a deeper dive into frames and marker data? The Profile Analyzer complements the existing Profiler  
Work.on.a.specific.time.budget.per.frame.  
Each frame will have a time budget based on your target frames per second (fps)  
Ideally, an application running at 30 fps will allow for approximately 3333 ms per  
frame ꢁ1000 ms / 30 fps) Likewise, a target of 60 fps leaves 1666 ms per frame  
For mobile, however, you cannot use this time consistently because the device  
will overheat and the OS will thermal throttle the CPU and GPU We recommend  
that you only use around 65% of the available time to allow cooldown between  
frames A typical frame budget will be approximately 22 ms per frame at 30 fps  
and 11 ms per frame at 60 fps  
Devices can exceed this for short periods of time (e g , for cutscenes or loading  
sequences) but not for a prolonged duration  
©
2021 Unity Technologies  
Determine.if.you.are.GPU-bound.or.CPU-bound  
The Profiler can tell you if your CPU is taking longer than your allotted frame  
budget or if the culprit is your GPU  
If you see the Gfx WaitForCommands marker, the render thread is ready,  
but you may be waiting for a bottleneck on the main thread  
If you frequently encounter Gfx WaitForPresent, that means the main thread  
was ready but was waiting for the GPU to present the frame  
Account.for.device.temperature..  
Most mobile devices do not have active cooling like their desktop counterparts  
Physical heat levels can directly impact performance  
If the device is running hot, the Profiler may report poor performance, even  
if it may not be cause for concern Combat profiling overhead by profiling in  
short bursts to keep the device cool and simulate realꢀworld conditions  
Test.on.a.min-spec.device  
There is a wide range of iOS and Android devices Test your project on the  
minimum device specifications that you want your application to support  
©
2021 Unity Technologies  
Memory  
Unity employs automatic memory management for your userꢀgenerated code  
and scripts Small pieces of data, like valueꢀtyped local variables, are allocated  
to the stack Larger pieces of data and longerꢀterm storage are allocated to the  
managed heap  
The garbage collector ꢁGCꢂ periodically identifies and deallocates unused heap  
memory While this runs automatically, the process of examining all the objects  
in the heap can cause the game to stutter or run slowly  
Optimizing your memory usage means being conscious of when you allocate and  
deallocate heap memory and minimizing the effect of garbage collection  
See Understanding the managed heap for more information  
©
2021 Unity Technologies  
Capture, inspect, and compare snapshots in the Memory Profiler  
Use.the.Memory.Profiler.  
This separate addꢀon (available as an Experimental or Preview package in  
the Package Manager) can take a snapshot of your managed heap memory,  
helping you spot problems like fragmentation and memory leaks  
Click in the Tree Map view to trace a variable to the native object holding  
on to memory Here, you can identify common memory consumption issues,  
like excessively large textures or duplicate assets  
Watch how you can use the Memory Profiler in Unity to improve memory usage  
Reduce.the.impact.of.garbage.collection.(GC).  
running your program code and only resumes normal execution when it  
has finished its work  
©
2021 Unity Technologies  
Be aware of certain unnecessary heap allocations, which could cause GC spikes:  
Strings:.In C#, strings are reference types, not value types Reduce unnecessary  
string creation or manipulation Avoid parsing stringꢀbased data files such  
as JSON and XML; store data in ScriptableObjects or formats such as  
MessagePack or Protobuf instead Use the StringBuilder class if you need  
to build strings at runtime  
Unity.function.calls: Be aware that some functions create heap allocations  
Cache references to arrays rather than allocating them in the middle of a loop  
Also, take advantage of certain functions that avoid generating garbage;  
for example, use GameObject CompareTag instead of manually comparing  
a string with GameObject tag (returning a new string creates garbage)  
Boxing:.Avoid passing a valueꢀtyped variable in place of a referenceꢀtyped  
variable This creates a temporary object, and the potential garbage that  
comes with it (e g , int.i.=.123;.object.o.ꢁ.i) implicitly converts the value  
type to a type object  
Coroutines:.Though yield does not produce garbage, creating a new  
WaitForSeconds object does Cache and reuse the WaitForSeconds object  
instead of creating it in the yield line  
LINQ.and.Regular.Expressions: Both of these generate garbage from  
behindꢀtheꢀscenes boxing Avoid LINQ and Regular Expressions if  
performance is an issue  
Time.garbage.collection.if.possible.  
If you are certain that a garbage collection freeze won’t affect a specific point  
in your game, you can trigger garbage collection with System GC Collect  
could potentially use this to your advantage  
©
2021 Unity Technologies  
Use.the.incremental.garbage.collector.to.split.the.GC.workload.  
Instead of using a single, long interruption of your program ’s execution, incremental  
garbage collection uses multiple, muchꢀshorter interruptions, distributing the  
workload over many frames If garbage collection is impacting performance, try  
enabling this option to see if it can significantly reduce the problem of GC spikes  
Use the Profile Analyzer to verify the benefit to your application  
Use the incremental garbage collector to reduce GC spikes  
©
2021 Unity Technologies  
Adaptive.Performance  
With Unity and Samsung’s Adaptive Performance, you can monitor the device’s  
thermal and power state to ensure that you’re ready to react appropriately  
When users play for an extended period of time, you can reduce your level of  
detail (or LODꢂ bias dynamically to help your game continue to run smoothly  
Adaptive Performance allows developers to increase performance in a  
controlled way while maintaining graphics fidelity  
While you can use Adaptive Performance APIs to fineꢀtune your application,  
this package also offers automatic modes In these modes, Adaptive Performance  
determines the game settings along several key metrics:  
Desired frame rate based on previous frames  
Device temperature level  
Device proximity to thermal event  
Device bound by CPU or GPU  
These four metrics dictate the state of the device, and Adaptive Performance  
tweaks the adjusted settings to reduce the bottleneck This is done by providing  
an integer value, known as an Indexer, to describe the state of the device  
©
2021 Unity Technologies  
Note that Adaptive Performance only works for Samsung devices  
To learn more about Adaptive Performance, you can view the  
samples we’ve provided in the Package Manager by selecting  
Package.Manager.>.Adaptive.Performance.>.Samples  
Each sample interacts with a specific scaler, so you can  
see how the different scalers impact your game We also  
recommend reviewing the End User Documentation to learn  
more about Adaptive Performance configurations and how  
you can interact directly with the API  
©
2021 Unity Technologies  
Programming.and.  
code.architecture  
The Unity PlayerLoop contains functions for interacting with the core of the  
game engine This treeꢀlike structure includes a number of systems that  
handle initialization and perꢀframe updates All of your scripts will rely on this  
PlayerLoop to create gameplay  
When profiling, you’ll see all of your project’s user code under the PlayerLoop  
(with Editor components under the EditorLoop)  
Your custom scripts, settings, and graphics can significantly impact how long each frame takes to calculate and render onscreen  
You can optimize your scripts with these tips and tricks  
Understand.the.Unity.PlayerLoop.  
Make sure you understand the execution order of Unity’s  
frame loop Every Unity script runs several event functions  
in a predetermined order You should understand the  
difference between Awake, Start, Update, and other  
functions that create the lifecycle of a script  
Refer to the Script Lifecycle Flowchart for event functions’  
specific order of execution  
Minimize.code.that.runs.every.frame.  
Consider whether code must run every frame  
Move unnecessary logic out of Update, LateUpdate,  
and FixedUpdate These event functions are convenient  
places to put code that must update every frame, but extract  
any logic that does not need to update with that frequency  
Whenever possible, only execute logic when things change  
Understand the PlayerLoop and the lifecycle of a script  
©
2021 Unity Technologies  
If you do need to use Update, consider running the code every n frames  
This is one way of applying time slicing, a common technique of distributing  
a heavy workload across multiple frames In this example, we run the  
ExampleExpensiveFunction once every three frames:  
private.int.interval.=.3;  
.
void.Updateꢂꢃ  
{
if.(Time frameCount.%.interval.==.0)  
{
.
......ExampleExpensiveFunctionꢂꢃ;  
}
}
Avoid.heavy.logic.in.Start/Awake.  
When your first scene loads, these functions get called for each object:  
Awake  
OnEnable  
Start  
Avoid expensive logic in these functions until your application renders its first  
frame Otherwise, you may encounter longer loading times than necessary  
Refer to the order of execution for event functions for details about the first  
scene load  
Avoid.empty.Unity.events.  
Even empty MonoBehaviours require resources, so you should remove blank  
Update or LateUpdate methods  
Use preprocessor directives if you are using these methods for testing:  
#
if.UNITY_EDITOR  
void.Updateꢂꢃ  
{
}
#
endif  
Here, you can freely use the Update in the Editor for testing without  
unnecessary overhead slipping into your build  
©
2021 Unity Technologies  
Remove.Debug.Log.statements.  
Log statements (especially in Update, LateUpdate, or FixedUpdate) can bog  
down performance Disable your Log statements before making a build  
To do this more easily, consider making a Conditional attribute along with  
a preprocessing directive For example, create a custom class like this:  
public.static.class.Logging  
{
.
.
.
.
.
.....[System Diagnostics Conditionalꢂ“ENABLE_LOG”ꢃ]  
.....static.public.void.Logꢂobject.messageꢃ  
.....{  
............UnityEngine Debug Logꢂmessageꢃ;  
.....}  
}
Adding a custom preprocessor directive lets you partition your scripts  
Generate your log message with your custom class If you disable the  
ENABLE_LOG preprocessor in the Player.Settings, all of your Log statements  
disappear in one fell swoop  
Use.hash.values.instead.of.string.parameters.  
Unity does not use string names to address Animator, Material, and Shader  
properties internally For speed, all property names are hashed into property  
IDs, and these IDs are actually used to address the properties  
Whenever using a Set or Get method on an Animator, Material, or Shader,  
use the integerꢀvalued method instead of the stringꢀvalued methods The string  
methods simply perform string hashing and then forward the hashed ID to the  
integerꢀvalued methods  
for Material and Shader property names  
©
2021 Unity Technologies  
Choose.the.right.data.structure  
Your choice of data structure can have a cumulative effect on efficiency or  
inefficiency as you iterate many thousands of times per frame Does it make  
more sense to use a List, Array, or Dictionary for your collection? Follow the  
correct structure  
Avoid.adding.components.at.runtime.  
Invoking AddComponent at runtime comes with some cost Unity must check for  
duplicate or other required components whenever adding components at runtime  
Instantiating a Prefab with the desired components already set up is generally  
more performant  
Cache.GameObjects.and.components.  
GameObject Find, GameObject GetComponent, and Camera main (in versions  
prior to 2020 2ꢂ can be expensive, so avoid calling them in Update methods  
Instead, call them in Start and cache the results  
For example, this demonstrates inefficient use of a repeated GetComponent call:  
void.Updateꢂꢃ  
{
.
.
.....Renderer.myRenderer.=.GetComponent<Rendererꢀꢂꢃ;  
.....ExampleFunctionꢂmyRendererꢃ;  
}
Instead, you can invoke GetComponent only once, as the result of the function  
is cached The cached result can be reused in Update without any further calls  
to GetComponent  
private.Renderer.myRenderer;  
void.Startꢂꢃ  
{
.
.....myRenderer.=.GetComponent<Rendererꢀꢂꢃ;  
}
void.Updateꢂꢃ  
{
.
.....ExampleFunctionꢂmyRendererꢃ;  
}
©
2021 Unity Technologies  
Use.object.pools.  
Instantiate and Destroy can generate garbage and garbage collection ꢁGCꢂ  
spikes and is generally a slow process Instead of instantiating and destroying  
GameObjects frequently (e g , shooting bullets from a gun), use pools of  
preallocated objects which can be reused and recycled  
In this example, the ObjectPool creates 20 PlayerLaser instances for reuse  
Create the reusable instances at a  
point in the game (e g , during a menu  
screen) when a CPU spike is less  
noticeable Track this “pool” of objects  
with a collection During gameplay,  
simply enable the next available  
instance when needed, disable objects  
instead of destroying them, and return  
them to the pool  
This reduces the number of managed  
allocations in your project and can  
prevent garbage collection problems  
Learn how to create a simple Object  
The pool of PlayerLaser objects is inactive and ready to shoot  
©
2021 Unity Technologies  
Use.ScriptableObjects.  
Store unchanging values or settings in a ScriptableObject instead of a  
MonoBehaviour The ScriptableObject is an asset that lives inside of the project  
that you only need to set up once It cannot be directly attached to a GameObject  
Create fields in the ScriptableObject to store your values or settings,  
then reference the ScriptableObject in your Monobehaviours  
In this example, a ScriptableObject called Inventory holds settings for various GameObjects  
Using those fields from the ScriptableObject can prevent unnecessary duplication  
of data every time you instantiate an object with that Monobehaviour  
Watch this Introduction to ScriptableObjects tutorial to see how ScriptableObjects  
©
2021 Unity Technologies  
Project.configuration  
There are a few Project Settings that can impact your mobile performance  
Reduce.or.disable.Accelerometer.Frequency.  
Unity pools your mobile’s accelerometer several times a second  
Disable this if it’s not being used in your application, or reduce its frequency  
for better performance  
Ensure your Accelerometer Frequency is disabled if you are not making use of it in your mobile game  
Disable.unnecessary.Player.or.Quality.settings  
In the Player settings, disable Auto.Graphics.API for unsupported platforms  
to prevent generating excessive shader variants Disable Target.Architectures  
for older CPUs if your application is not supporting them  
In the Quality settings, disable unneeded Quality levels  
Disable.unnecessary.physics  
If your game is not using physics, uncheck Auto.Simulation and Auto.Sync.  
Transforms These will just slow down your application with no discernible benefit  
©
2021 Unity Technologies  
Choose.the.right.frame.rate.  
Mobile projects must balance frame rates against battery life and thermal  
throttling Instead of pushing the limits of your device at 60 fps, consider  
running at 30 fps as a compromise Unity defaults to 30 fps for mobile  
You can also adjust the frame rate dynamically during runtime with  
Application targetFrameRate For example, you could even drop below  
30 fps for slow or relatively static scenes and reserve higher fps settings  
for gameplay  
Avoid.large.hierarchies  
Split your hierarchies! If your GameObjects do not need to be nested  
in a hierarchy, simplify the parenting Smaller hierarchies benefit from  
multithreading to refresh the Transforms in your scene Complex hierarchies incur  
unnecessary Transform computations and more cost to garbage collection  
See Optimizing the Hierarchy and this Unite talk for best practices  
with Transforms  
Transform.once,.not.twice  
Also, when moving Transforms, use Transform SetPositionAndRotation  
to update both position and rotation at once This avoids the overhead  
of modifying a transform twice  
is to parent and reposition during instantiation:  
GameObject Instantiateꢂprefab,.parentꢃ;  
GameObject Instantiateꢂprefab,.parent,.position,.rotationꢃ;  
For more details about Object Instantiate, please see the Scripting API  
Assume.Vsync.is.enabled.  
Mobile platforms won’t render halfꢀframes Even if you disable Vsync in the  
Editor (Project.Settings.>.Quality), Vsync is enabled at the hardware level  
If the GPU cannot refresh fast enough, the current frame will be held,  
effectively reducing your fps  
©
2021 Unity Technologies  
The Boat Attack demo  
project was created using the  
Universal Render Pipeline.  
Assets  
The asset pipeline can dramatically impact your application’s performance  
An experienced technical artist can help your team define and enforce asset  
formats, specifications, and import settings  
Don’t rely on default settings Use the platformꢀspecific override tab to optimize  
assets such as textures and mesh geometry Incorrect settings may yield larger  
build sizes, longer build times, and poor memory usage Consider using the  
Presets feature to help customize baseline settings for a specific project to  
ensure optimal settings  
Unity Learn  
©
2021 Unity Technologies  
Import.textures.correctly.  
Most of your memory will likely go to textures, so the import settings here are  
critical In general, follow these guidelines:  
Lower.the.Max.Size:.Use the minimum settings  
that produce visually acceptable results  
This is nonꢀdestructive and can quickly reduce  
your texture memory  
Use.powers.of.two.(POT)ꢄ.Unity requires POT  
texture dimensions for mobile texture compression  
formats ꢁPVRCT or ETCꢂ  
Atlas.your.textures:.Placing multiple textures into  
a single texture can reduce draw calls and speed  
thirdꢀparty Texture Packer to atlas your textures  
Toggle.off.the.Read/Write.Enabled.option:..  
When enabled, this option creates a copy in both  
CPU- and GPUꢀaddressable memory, doubling the  
texture’s memory footprint In most cases, keep this  
disabled If you are generating textures at runtime,  
enforce this via Texture2D Apply, passing in  
makeNoLongerReadable set to true  
Disable.unnecessary.Mip.Maps: Mip Maps are not  
needed for textures that remain at a consistent size  
onꢀscreen, such as 2D sprites and UI graphics  
(leave Mip Maps enabled for 3D models that vary  
their distance from the camera)  
Proper texture import settings will help optimize your build size  
©
2021 Unity Technologies  
Compress.textures.  
Consider these two examples using the same model and texture The settings  
on the left consume almost eight times the memory as those on the right,  
without much benefit in visual quality  
Uncompressed textures require more memory  
Use Adaptive Scalable Texture Compression ꢁATSCꢂ for both iOS and Android  
The vast majority of games in development target minꢀspec devices that  
support ATSC compression  
The only exceptions are:  
iOS games targeting A7 devices or lower (e g , iPhone 5, 5S, etc ) – use  
PVRTC  
Android games targeting devices prior to 2016 ꢃ use ETC2 ꢁEricsson  
Texture Compression)  
If the quality of compressed formats such as PVRTC and ETC isn’t sufficiently  
high, and if ASTC is not fully supported on your target platform, try using 16ꢀbit  
textures instead of 32ꢀbit textures  
©
2021 Unity Technologies  
Adjust.mesh.import.settings  
Much like textures, meshes can consume excess memory if not imported  
carefully To minimize meshes’ memory consumption:  
Compress.the.mesh:.Aggressive  
compression can reduce disk space  
(memory at runtime, however, is unaffected)  
Note that mesh quantization can result in  
inaccuracy, so experiment with compression  
levels to see what works for your models  
Disable.Read/Write:.Enabling this option  
duplicates the mesh in memory, keeping one  
copy of the mesh in system memory and  
another in GPU memory In most cases, you  
should disable it (in Unity 20192 and earlier,  
this option is checked by default)  
Disable.rigs.and.BlendShapes:.If your  
mesh does not need skeletal or  
blendshape animation, disable these  
options wherever possible  
Disable.normals.and.tangents,.if.possible:..  
If you are certain the mesh ’s material will not  
need normals or tangents, uncheck these  
options for extra savings  
Check your mesh import settings  
Check.your.polygon.counts.  
Higherꢀresolution models mean more memory usage and potentially longer  
GPU times Does your background geometry need half a million polygons?  
Consider cutting down models in your DCC package of choice Delete unseen  
polygons from the camera’s point of view Use textures and normal maps for fine  
detail instead of highꢀdensity meshes  
Automate.your.import.settings.using.the.AssetPostprocessor.  
The AssetPostprocessor allows you to run scripts when importing assets  
This allows you to customize settings before and/or after importing models,  
textures, audio, and so on  
©
2021 Unity Technologies  
Use.the.Addressable.Asset.System  
The Addressable Asset System provides a simplified way to manage your  
content, loading AssetBundles by “address” or alias This unified system loads  
asynchronously from either a  
local path or a remote content  
delivery network ꢁCDNꢂ  
If you split your nonꢀcode assets ꢁModels, Textures, Prefabs, Audio, and even  
entire Scenes) into an AssetBundle, you can separate them as downloadable  
content ꢁDLCꢂ  
application Cloud Content Delivery lets you host and deliver your game  
content to players as they progress through the game  
Load assets by “address” using the Addressable Asset System  
Click here to see how the Addressable Asset System can take the pain out of  
asset management  
©
2021 Unity Technologies  
Boat Attack demo project created using the Universal Render Pipeline.  
Graphics.and..  
GPU.optimization  
Each frame, Unity determines which objects must be rendered and then  
creates draw calls A draw call is a call to the graphics API to draw objects  
(e g , a triangle), while a batch is a group of draw calls to be executed together  
As your projects become more complex, you’ll need a pipeline that optimizes  
the workload on your GPU The Universal.Render.Pipeline.(URP) currently  
uses a singleꢀpass forward renderer to bring highꢀquality graphics to your  
mobile platform (deferred rendering will be available in future releases)  
The same physically based Lighting and Materials from consoles and PCs  
can also scale to your phone or tablet  
©
2021 Unity Technologies  
The following guidelines can help you to speed up your graphics  
Batch.your.draw.calls.  
Batching objects to be drawn together minimizes the state changes needed to  
draw each object in a batch This leads to improved performance by reducing  
the CPU cost of rendering objects Unity can combine multiple objects into  
fewer batches using several techniques:  
Dynamic.batching: For small meshes, Unity can group and transform  
vertices on the CPU, then draw them all in one go Note: Only use this if  
you have enough lowꢀpoly meshes (less than 900 vertex attributes and  
no more than 300 vertices) The dynamic batcher won’t batch larger  
meshes than this, so enabling it will waste CPU time every frame looking  
for small meshes to batch  
Static.batching: For nonꢀmoving geometry, Unity can reduce draw  
calls for any meshes sharing the same material It is more efficient than  
dynamic batching, but it uses more memory  
GPU.instancing: If you have a large number of identical objects, this  
technique batches them more efficiently using graphics hardware  
Organize your GameObjects to take advantage of these batching techniques  
©
2021 Unity Technologies  
Use.the.Frame.Debugger.  
The Frame Debugger shows how each frame  
is constructed from individual draw calls  
This is an invaluable tool for troubleshooting  
your shader properties and can help you  
analyze how the game is rendered  
Avoid.too.many.dynamic.lights.  
The URP reduces the number of draw calls  
compared to the legacy forward renderer  
Avoid adding too many dynamic lights to your  
mobile application Consider alternatives like  
custom shader effects and light probes for  
dynamic meshes, as well as baked lighting for  
static meshes  
For the specific limits of URP and Builtꢀin  
The Frame Debugger breaks each frame into its separate steps  
Disable.shadows.  
Shadow casting can be disabled per MeshRenderer and light Disable shadows  
whenever possible to reduce draw calls  
You can also create fake shadows using a blurred texture applied to a simple  
mesh or quad underneath your characters Alternately, create blob shadows  
with custom shaders  
Disable shadow casting to reduce draw calls  
©
2021 Unity Technologies  
Bake.your.lighting.into.Lightmaps.  
Add dramatic lighting to your static  
geometry using Global Illumination ꢁGIꢂ  
Mark objects with Contribute.GI so  
you can store highꢀquality lighting in  
the form of Lightmaps  
Baked shadows and lighting can then  
render without a performance hit at  
runtime The Progressive CPU and  
GPU Lightmapper can accelerate the  
baking of Global Illumination  
Enable Contribute GI  
Adjust the Lightmapping.Settings (Windows.>.Rendering.>.Lighting.Settings and Lightmap size to limit memory usage  
getting started with Lightmapping in Unity  
©
2021 Unity Technologies  
Use.Light.Layers.  
For complex scenes with multiple lights, separate your objects using layers,  
then confine each light’s influence to a specific culling mask  
Layers can limit your light’s influence to a specific culling mask  
Use.Light.Probes.for.moving.objects  
Light Probes store baked lighting information about the empty space in your  
Scene and provide highꢀquality lighting (both direct and indirect) They use  
Spherical Harmonics, which calculate very quickly compared to dynamic lights  
Light Probes illuminate dynamic objects in the background  
©
2021 Unity Technologies  
Use.Level.of.Detail.(LOD)..  
As objects move into the distance,  
use simpler meshes with simpler  
materials and shaders to aid GPU  
performance  
on Unity Learn for more detail  
Example of a mesh using a LOD Group  
Source meshes, modeled at varying resolutions  
Use.Occlusion.Culling.to.remove.hidden.objects.  
Objects hidden behind other objects can potentially still render and cost  
resources Use Occlusion Culling to discard them  
While frustum culling outside the camera view is automatic, occlusion culling is  
a baked process Simply mark your objects as Static.Occluders or Occludees,  
then bake through the Window.>.Rendering.>.Occlusion.Culling dialog  
Though not appropriate for every scene, culling can improve performance  
in many cases  
Check out the Working with Occlusion Culling tutorial for more information  
Avoid.mobile.native.resolution.  
Phones and tablets have become increasingly advanced, with newer devices  
sporting very high resolutions  
Use Screen SetResolutionꢂwidth,.height,.falseꢃ to lower the output resolution  
and regain some performance Profile multiple resolutions to find the best  
balance between quality and speed  
©
2021 Unity Technologies  
Limit.use.of.cameras  
Each camera incurs some overhead, whether it’s doing meaningful work or not  
Only use camera components necessary for rendering On lowerꢀend mobile  
platforms, each camera can use up to 1 ms of CPU time  
Keep.shaders.simple.  
The Universal Render Pipeline  
includes several lightweight Lit  
and Unlit shaders that are already  
optimized for mobile platforms  
Try to keep your shader variations as  
low as possible, since this can have  
a dramatic effect on runtime memory  
usage If the default URP shaders  
don’t suit your needs, you can  
customize the look of your materials  
using Shader Graph Find out how  
Shader Graph here  
Create custom shaders with the Shader Graph  
Minimize.overdraw.and.alpha.blending  
Avoid drawing unnecessary transparent or semiꢀtransparent images  
Mobile platforms are greatly impacted by the resulting overdraw and alpha  
blending Don’t overlap barely visible images or effects You can check  
Limit.Post-processing.effects.  
Fullscreen Postꢀprocessing effects  
like glows can dramatically slow  
performance Use them cautiously  
in your title’s art direction  
Keep Postꢀprocessing simple in mobile applications  
©
2021 Unity Technologies  
Be.careful.with.Renderer material.  
Accessing Renderer material in scripts duplicates the material and returns  
a reference to the new copy This breaks any existing batch that already  
includes the material If you wish to access the batched object’s material,  
Optimize.SkinnedMeshRenderers.  
Rendering skinned meshes is expensive Make sure that every object using  
a SkinnedMeshRenderer requires it If a GameObject only needs animation  
some of the time, use the BakeMesh function to freeze the skinned mesh in  
a static pose, and swap to a simpler MeshRenderer at runtime  
Minimize.Reflection.Probes.  
A Reflection Probe can create realistic reflections, but this can be very costly  
in terms of batches Use lowꢀresolution cubemaps, culling masks, and texture  
compression to improve runtime performance  
©
2021 Unity Technologies  
User.interface  
Unity UI ꢁUGUIꢂ is often a source of performance issues The Canvas  
component generates and updates meshes for the UI elements and issues  
draw calls to the GPU Its functioning can be expensive, so keep the following  
factors in mind when working with UGUI  
Divide.your.Canvases  
If you have one large Canvas with thousands of elements, updating a single UI  
element forces the whole Canvas to update, potentially generating a CPU spike  
Take advantage of UGUI’s ability to support multiple Canvases Divide UI  
elements based on how frequently they need to be refreshed Keep static UI  
elements on a separate Canvas, and keep dynamic elements that update at  
the same time on smaller subꢀcanvases  
Ensure that all UI elements within each Canvas have the same Z value,  
materials, and textures  
Hide.invisible.UI.elements.  
You may have UI elements that only appear sporadically in the game  
(
e g , a health bar that appears only when a character takes damage)  
If your invisible UI element is active, it might still be using draw calls  
Explicitly disable any invisible UI components and reꢀenable them as needed  
If you only need to turn off the Canvas ’s visibility, disable the Canvas component  
rather than GameObject This can save rebuilding the meshes and vertices  
Limit.GraphicRaycasters.and.disable.Raycast.Target.  
Input events like onꢀscreen touches or clicks require the GraphicRaycaster  
component This simply loops through each input point on screen and checks  
if it’s within a UI’s RectTransform  
Remove the default GraphicRaycaster from the top Canvas in the hierarchy  
Instead add the GraphicRaycaster only to the individual elements that need  
to interact (buttons, scroll rects, and so on)  
Disable Ignore Reversed Graphics, which is active by default  
©
2021 Unity Technologies  
Also, disable Raycast.Target on all UI text and images that don’t need it  
If the UI is complex with many elements, all of these small changes can reduce  
unnecessary computation  
Disable Raycast Target if possible  
Avoid.Layout.Groups  
Layout Groups update inefficiently, so use them sparingly Avoid them entirely  
if your content isn’t dynamic, and use anchors for proportional layouts instead  
Alternately, create custom code to disable the Layout Group components after  
they set up the UI  
If you do need to use Layout Groups ꢁHorizontal, Vertical, Grid) for your dynamic  
elements, avoid nesting them to improve performance  
Layout Groups can lower performance, especially when nested  
Avoid.large.List.and.Grid.views.  
Large List and Grid views are expensive If you need to create a large List or  
Grid view (e g , an inventory screen with hundreds of items), consider reusing  
a smaller pool of UI elements rather than creating a UI element for every item  
Check out this sample GitHub project to see this in action  
©
2021 Unity Technologies  
Avoid.numerous.overlaid.elements  
Layering lots of UI elements (e g , cards stacked in a card battle game) creates  
overdraw Customize your code to merge layered elements at runtime into  
fewer elements and batches  
Use.multiple.resolutions.and.aspect.ratios.  
With mobile devices now using very different resolutions and screen sizes,  
create alternate versions of the UI to provide the best experience per device  
Use the Device Simulator to preview the UI across a wide range of supported  
devices You can also create virtual devices in XCode and Android Studio  
Preview a variety of screen formats using the Device Simulator  
When.using.a.fullscreen.UI,.hide.everything.else.  
If your pause screen or start screen covers everything else in the scene,  
disable the camera rendering the 3D scene Likewise, disable any background  
Canvas elements hidden behind the top Canvas  
Consider lowering the Application targetFrameRate during a fullscreen UI,  
since you should not need to update at 60 fps  
©
2021 Unity Technologies  
Assign.the.Camera.to.World.Space.and.Camera.Space.Canvases.  
Leaving the Event or Render.Camera field blank forces Unity to fill  
in Camera main, which is unnecessarily expensive  
Consider using Screen.Space.–.Overlay for your Canvas RenderMode  
if possible, since that does not require a camera  
When using World Space Render Mode, make sure to fill in the Event Camera  
©
2021 Unity Technologies  
Audio  
Though audio is not normally a performance  
bottleneck, you can still optimize to  
save memory  
Make.sound.clips.mono.when.possible  
If you are using 3D spatial audio, author  
your sound clips as mono (single channel)  
or enable the Force To Mono setting  
A multichannel sound used positionally  
at runtime will be flattened to a mono  
source, thus increasing CPU cost and  
wasting memory  
Use.original.uncompressed.WAV.files..  
as.your.source.assets.when.possible.  
If you use any compressed format (such as  
MP3 or Vorbis), then Unity will decompress  
it and recompress it during build time  
This results in two lossy passes, degrading  
the final quality  
Compress.the.clip.and.reduce.the.  
compression.bitrate.  
Reduce the size of your clips and memory  
usage with compression:  
Use Vorbis for most sounds (or MP3  
for sounds not intended to loop)  
Optimize the Import Settings of your AudioClips  
Use ADPCM for short, frequently used  
sounds (e g , footsteps, gunshots)  
This shrinks the files compared to uncompressed PCM but is fast  
to decode during playback  
Sound effects on mobile devices should be 22,050 Hz at most  
Using lower settings usually has minimal impact on the final quality,  
but use your own ears to judge  
©
2021 Unity Technologies  
Choose.the.proper.Load.Type.  
The setting varies per clip size  
Small.clips.(ꢅ.200.kb should Decompress.on.Load This incurs CPU cost  
and memory by decompressing a sound into raw 16ꢀbit PCM audio data,  
so it’s only desirable for short sounds  
Medium.clips.(>=.200.kbꢃ should remain Compressed.in.Memory  
Large.files.ꢂbackground.musicꢃ should be set to Streaming  
Otherwise, the entire asset will be loaded into memory at once  
Unload.muted.AudioSources.from.memory.  
When implementing a mute button, don’t simply set the volume to 0 You can  
Destroy the AudioSource component to unload it from memory, provided the  
player does not need to toggle this on and off very often  
©
2021 Unity Technologies  
Unity’s Mecanim system is fairly sophisticated If possible, limit your usage  
on mobile using the settings that follow  
Use.generic.versus.humanoid.rigs.  
By default, Unity imports animated models with the Generic Rig, but  
developers often switch to the Humanoid Rig when animating a character  
A Humanoid Rig consumes 30ꢃ50% more CPU time than the equivalent  
Generic Rig because it calculates inverse kinematics and animation  
retargeting each frame, even when not in use If you don’t need these  
specific features of the Humanoid Rig, use the Generic Rig  
©
2021 Unity Technologies  
Avoid.excessive.use.of.Animators.  
Animators are primarily intended for humanoid characters but are often  
used to animate single values (e g , the alpha channel of a UI element)  
Avoid overusing Animators, particularly in conjunction with UI elements  
Whenever possible, use the legacy Animation components for mobile  
Consider creating tweening functions or using a thirdꢀparty library for  
simple animations (e g , DOTween)  
Animators are potentially expensive  
©
2021 Unity Technologies  
Physics  
Unity’s builtꢀin Physics ꢁNvidia PhysXꢂ can be expensive on mobile The following  
tips may help you squeeze out more frames per second  
Optimize.your.settings  
In the PlayerSettings, check Prebake.Collision.Meshes whenever possible  
Enable Prebake Collision Meshes  
Make sure that you edit your Physics.  
settings (Project.Settings.>.Physics)  
as well Simplify your Layer.Collision.  
Matrix wherever possible  
Disable Auto.Sync.Transforms and  
enable Reuse.Collision.Callbacks  
Modify the physics project settings to squeeze out more performance  
©
2021 Unity Technologies  
Keep an eye on the Physics module of the Profiler for performance issues  
Simplify.colliders.  
Mesh colliders can be expensive Substitute more complex  
mesh colliders with simpler primitive or mesh colliders to  
approximate the original shape  
Move.a.Rigidbody.using.physics.methods.  
Use class methods like MovePosition or AddForce  
to move your Rigidbody objects Translating their  
Transform components directly can lead to physics world  
recalculations, which can be expensive in complex scenes  
Move physics bodies in FixedUpdate rather than Update  
Fix.the.Fixed.Timestep.  
The default Fixed.Timestep in the Project Settings is  
0
02 ꢁ50 Hz) Change this to match your target frame rate  
(for example 0 03 for 30 fps)  
Use primitives or simplified meshes for colliders  
Otherwise, if your frame rate drops at runtime, that  
means Unity would call FixedUpdate multiple times per  
frame, potentially creating a CPU performance issue with  
physicsꢀheavy content  
The Maximum.Allowed.Timestep limits how much time  
physics calculations and FixedUpdate events can use in the  
event the frame rate drops Lowering this value means that  
during a performance hitch, physics and animation may  
slow down, but it also reduces their impact on frame rate  
Modify the Fixed Timestep to match your target frame rate, and lower the Maximum  
Allowed Timestep to reduce performance glitches  
©
2021 Unity Technologies  
Visualize.with.the.Physics.Debugger  
Use the Physics Debug window (Window.>.Analysis.>.Physics.Debugger)  
to help troubleshoot any problem colliders or discrepancies This shows  
a colorꢀcoded indicator of what GameObjects should be able to collide  
with one another  
The Physics Debugger helps you visualize how your physics objects can interact with each other  
in the Unity documentation  
©
2021 Unity Technologies  
Workflow.and.  
collaboration  
Building an application in Unity is a large endeavor that will often involve many  
developers Make sure that your project is set up optimally for your team  
Use.version.control.  
Everyone should be using some type of version control Make sure your Editor.  
Settings have Asset.Serialization.Mode set to Force.Text  
If you’re using an external version control system (such as Git) in the Version.  
Control settings, make sure the Mode is set to Visible.Meta.Files  
Unity also has a builtꢀin YAML (a humanꢀreadable, dataꢀserialization language)  
tool specifically for merging Scenes and Prefabs For more information,  
see Smart Merge in the Unity documentation  
Version control is essential for working as part of a team It can help you track  
down bugs and bad revisions Follow good practices like using branches  
and tags to manage milestones and releases  
Check out Plastic SCM, our recommended version control solution for Unity  
game development  
Break.up.large.Scenes.  
Large, single Unity Scenes do not lend themselves well to collaboration  
Break your levels into many smaller Scenes so that artists and designers can  
collaborate better on a single level while minimizing the risk of conflicts  
At runtime, your project can load Scenes additively using  
SceneManager LoadSceneAsync passing the LoadSceneMode Additive  
parameter mode  
©
2021 Unity Technologies  
Remove.unused.resources.  
Watch out for any unused assets that come bundled with thirdꢀparty plugꢀins and  
libraries Many include embedded test assets and scripts, which will become part  
of your build if you don’t remove them Strip out any unneeded resources left over  
from prototyping  
Speed.Up.sharing.with.Unity.Accelerator.  
The Unity Accelerator is a proxy and cache for the Collaborate service that allows  
you to share Unity Editor content faster If your team is working on the same local  
network, you don’t need to rebuild portions of your project, significantly reducing  
download time When used with Unity Teams Advanced, the Accelerator also  
shares source assets  
©
2021 Unity Technologies  
Unity.Integrated.  
Success  
If you need personalized attention, consider Unity Integrated Success  
Integrated Success is much more than a support package Integrated Success  
customers also have the option to add read and modification access to Unity  
source code This access is available for development teams that want to deep  
dive into the source code to adapt and reuse it for other applications  
Get.a.Project.Review.  
Project Reviews are an essential part of the Integrated Success package  
Whenever possible, we travel to our customers and typically spend two full  
days familiarizing ourselves with their projects We use various profiling  
tools to detect performance bottlenecks, factoring in existing requirements  
and design decisions We also identify points where performance could be  
optimized for greater speed, stability, and efficiency  
For wellꢀarchitected projects that have low build times (modular scenes, heavy  
usage of AssetBundles, etc ), we perform changes while onsite and reprofile to  
uncover new issues  
In instances where we are unable to solve problems directly, we capture as much  
information as possible Then, we conduct further investigation back at the Unity  
offices, consulting specialized developers across our R&D departments if need be  
Though deliverables can vary depending on the needs of the customers,  
typically a written report summarizes our findings and provides recommendations  
Our goal is to always provide the greatest value to our customers by helping them  
identify potential blockers, assess risk, validate solutions and ensure that they  
are following best practices moving forward  
Developer.Relations.Manager.(DRM).  
In addition to a Project Review, Unity Integrated Success also comes with  
a Developer Relations Manager ꢁDRMꢂ, a strategic Unity advisor who will quickly  
become an extension of your team to help you get the most out of Unity  
Your DRM provides you with the dedicated technical and operational expertise  
required to preempt issues and keep your projects running smoothly, right up  
to launch and beyond  
To learn more about an Integrated Success package and Project Reviews,  
please reach out to your Unity sales or fill out this form  
©
2021 Unity Technologies  
Conclusion  
Performance optimization is a vast topic Understand how your mobile hardware  
operates, along with its limitations In order to find an efficient solution that  
satisfies your design requirements, you will need to master Unity’s classes and  
components, algorithms and data structures, and your platform’s profiling tools  
Of course, a little bit of creativity helps here, too  
©
2021 Unity Technologies